/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "bsp.h"
#include "stdint.h"
#include "os_obj.h"
#include "systask.h"

#include "nor_cmd.h"
#include "extblockflashlog.h"

#include "str_ext.h"
#include "common.h"

/*****************************************************************************
* @brief   extern .
*****************************************************************************/
extern const block_log_cfg_type blog_cfg;
extern const block_log_mix_type log_mix;

/*****************************************************************************
* @brief   hal .
*****************************************************************************/
void LogErase(uint32_t AddrBase);							 /*从指定地址擦除，Nums指定擦除的扇区个数*/
void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len); /*向指定指定地址编程数据*/
void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len);	 /*读取块数据*/
void LogFlashFullCallBack(uint8_t mode);					 /*存满回调*/

// 日志数据
typedef struct
{
	sig_time_type time;
	uint16_t temp_pv;
	uint16_t temp_sv;
	uint16_t humi_pv;
	uint16_t humi_sv;
	uint16_t ver[24];
} log_dat_type;

log_dat_type log_dat;

// 日志缓存配置
log_buff_api_ref(log_buff_cfg);
log_buff_info_type log_buff_info;
const log_buff_cfg_type log_buff_cfg = {
	.buff_amount = 4,
	.first_base = 0x08080000,
	.buff_size = 32 * 1024,
	.sector_size = 4 * 1024,
	.ext_page_size = 2 * 1024,
	.data_size = 48,
	.p_data = (uint8_t *)&log_dat,
	.info = &log_buff_info,
	.erase = LogErase,
	.program = LogProgram,
	.read = LogRead,
	.full_callback = LogFlashFullCallBack,
	.api = log_buff_api_name(log_buff_cfg)};

log_buff_api_make(log_buff_cfg);

// 日志缓存管理
typedef struct
{
	char init;
	int32_t search_res;
	sig_time_type sig_time;
	TIME_Type rtc_time;
	log_dat_type log_rd;
	uint16_t save_req;
	uint16_t read_req;
	uint8_t clr_req;
	uint8_t alain_req;
	int8_t tm_search_req;
	uint8_t hd_search_req;
	uint8_t init_req;
} log_buff_test_type;

log_buff_test_type log_buff_obj;

/*-----------------------------------------------------------------------------------------------------*
* log_buff_test
*-----------------------------------------------------------------------------------------------------*/
void log_buff_test(void)
{
	if (!log_buff_obj.init)
	{
		sig_time_type sigt_end, sigt_start;
		uu8 buff[32];

		log_buff_obj.init = 1;

		// 设置时间
		rtc_time_run_sec(&log_buff_obj.rtc_time, 30);
		rtc_time_run_min(&log_buff_obj.rtc_time, 360);
		rtc_time_run_hour(&log_buff_obj.rtc_time, 15 * 366 * 24);

		log_buff_init(&log_buff_cfg);

		if (log_buff_cfg.info->site_next > 0)
		{
			log_buff_read(&log_buff_cfg, log_buff_cfg.info->site_next - 1, &log_dat);
			sigt_end.val = log_dat.time.val;
		}

		block_log_check(&blog_cfg);

		// 读取首条日志
		block_log_mix_read(&log_mix, blog_cfg.Info->block_start * log_buff_cfg.info->sits_total, 1, &log_buff_obj.log_rd);
		sigt_start.val = log_buff_obj.log_rd.time.val;

		// 显示首尾时间
		sig_to_ascii(sigt_start, buff);
		gd25_dbg_print("log start time : %s \n", buff);
		sig_to_ascii(sigt_end, buff);
		gd25_dbg_print("log end time : %s \n", buff);
	}
	
	// 清除日志缓存
	if (log_buff_obj.clr_req)
	{
		LogErase(log_buff_cfg.info->flash_base);
		LogErase(log_buff_cfg.info->flash_base + 4 * 1024);
		LogErase(log_buff_cfg.info->flash_base + 8 * 1024);
		log_buff_init(&log_buff_cfg);
		log_buff_obj.clr_req = 0;
	}

	// 保存日志
	if (log_buff_obj.save_req)
	{
		log_buff_obj.save_req--;
		rtc_time_run_min(&log_buff_obj.rtc_time, 2);
		log_dat.time = time_to_sig(&log_buff_obj.rtc_time);
		log_dat.temp_pv = (log_dat.temp_pv + 3) & 0x7FF;
		log_dat.humi_pv = (log_dat.humi_pv + 5) & 0x3FF;
		log_buff_save(&log_buff_cfg);
	}

	// 读取一条日志
	if (log_buff_obj.read_req)
	{
		log_buff_cfg.api->read(log_buff_obj.read_req, &log_buff_obj.log_rd);
		log_buff_obj.read_req = 0;
	}

	// 日志对齐
	if (log_buff_obj.alain_req)
	{
		log_buff_obj.alain_req = 0;
		log_buff_align(&log_buff_cfg);
	}

	// 初始化
	if (log_buff_obj.init_req)
	{
		log_buff_obj.init_req = 0;
		log_buff_init(&log_buff_cfg);
	}

	// 搜索
	if (log_buff_obj.tm_search_req)
	{
		NOP1();
		if (log_buff_obj.tm_search_req < 0)
			log_buff_obj.search_res = log_buff_time_search(&log_buff_cfg, log_buff_obj.sig_time, -1);
		else
			log_buff_obj.search_res = log_buff_time_search(&log_buff_cfg, log_buff_obj.sig_time, 1);
		log_buff_obj.tm_search_req = 0;

		if (log_buff_obj.search_res >= 0)
			log_buff_obj.read_req = log_buff_obj.search_res;

		gd25_dbg_print("log buff search res: 0x%x \n", log_buff_obj.search_res);
	}

	if (log_buff_obj.hd_search_req)
	{
		log_buff_cfg.api->head_search(log_buff_obj.hd_search_req, (void *)&log_buff_obj.search_res);
		log_buff_obj.hd_search_req = 0;
	}
}

/*--------------------------------------------------------------------------------*
* log buff hal
*---------------------------------------------------------------------------------*/
void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	FLASH_UnlockBank2();

	Len /= 4;
	while (Len--)
	{
		FLASH_ProgramWord(Addr, *(uint32_t *)Data);
		Addr += 4;
		Data += 4;
	}

	FLASH_LockBank2();
}

void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	Len /= 4;

	while (Len--)
	{
		*(uint32_t *)Data = inpw(Addr);
		;
		Addr += 4;
		Data += 4;
	}
}

void LogErase(uint32_t AddrBase)
{
	int index;

	FLASH_UnlockBank2();

	for (index = 0; index < 4 * 1024 / 2048; index++)
	{
		FLASH_ErasePage(AddrBase + index * 2048);
	}

	FLASH_LockBank2();
}

void LogFlashFullCallBack(uint8_t mode)
{
	gd25_dbg_print("log buffer full call back \n");
	block_log_save(&blog_cfg);
}
